<template>
  <div class="flex flex-col" :class="{ 'bg-blue-200': active }">
    <div class="flex flex-row items-center cursor-pointer" @click.stop="onUpdateModelValue" v-loading="!deviceInited">
      <div class="flex-1 min-w-0 py-4" @click.stop="onImgClick('click', $event)">
        {{ info?.key }}
      </div>
    </div>
  </div>
</template>
<script setup>
import { computed, inject, onBeforeUnmount, onMounted, ref, shallowRef, toValue, watch, watchEffect } from 'vue';
import { v4 } from 'uuid'
import { io } from 'socket.io-client'

const $emits = defineEmits(['changeActive', 'changeImgPath'])
const activeKeys = defineModel()
const serverUrl = ref('http://localhost:3000')
const props = defineProps({
  info: {
    type: Object,
    defaulat: () => ({})
  },
  refreshImageDelay: {
    type: Number,
    defaulat: 10000
  },
  active: {
    type: Boolean,
    defaulat: false
  }
})
const requestIdKeys = {}
const deviceInited = ref(false)
const deviceScreenKey = ref(1)
const deviceWidth = ref(0)
const deviceHeight = ref(0)
const imageBound = ref()
const mousePosition = ref()
const imgPath = shallowRef()

const deviceId = computed(() => {
  if (props.info?.type === 'ip') {
    return `${props.info.host}:${props.info.port}`
  }

  return ''
})

const deviceImg = computed(() => {
  return serverUrl.value + '/get-device-image?deviceId=' + deviceId.value + '&deviceScreenKey=' + deviceScreenKey.value
})

// const socketRef = inject('socketRef')
const socketRef = shallowRef()

const onImgLoad = evt => {
  deviceWidth.value = evt.target.naturalWidth
  deviceHeight.value = evt.target.naturalHeight
  imageBound.value = evt.target.getBoundingClientRect()

  setTimeout(() => {
    deviceScreenKey.value++
  }, props.refreshImageDelay);
}

function calacXY(clientX, clientY) {
  const imageBoundValue = toValue(imageBound)
  const deviceWidthValue = toValue(deviceWidth)
  const deviceHeightValue = toValue(deviceHeight)
  let startX = clientX - imageBoundValue?.left || 0
  let startY = clientY - imageBoundValue?.top || 0

  let imageWidth = imageBoundValue?.width || 1
  let imageHeight = imageBoundValue?.height || 1

  if (startX < 0) {
    startX = 0
  }

  if (startY < 0) {
    startY = 0
  }

  return {
    x: Math.ceil(deviceWidthValue * (startX / imageWidth)),
    y: Math.ceil(deviceHeightValue * (startY / imageHeight))
  }
}

function onImgClick(type, e) {
  if (type === 'click') {
    $emits('changeActive', props.info.key)
  }
}

const sendMsg = (type, msg) => {
  const socket = toValue(socketRef)

  if (!socket) {
    return
  }

  const requestId = v4()

  requestIdKeys[requestId] = true

  socket.emit(type, {
    requestId,
    data: msg
  })

  return requestId
}

const sendCommand = (data) => {
  sendMsg('command', data)
}

const ensureRequestId = (msg, callback) => {
  const requestId = msg.requestId

  if (requestIdKeys[requestId]) {
    delete requestIdKeys[requestId]
    callback(msg.data)
  }
}

const initDone = (msg) => {
  ensureRequestId(msg, data => {
    console.log('init-done', data)
    deviceInited.value = true
  })
}

let _refreshScreenInterval = null

const startRefreshScreen = () => {
  _refreshScreenInterval = setInterval(() => {
    deviceScreenKey.value++
  }, props.refreshImageDelay);
}

const stopRefreshScreen = () => {
  clearInterval(_refreshScreenInterval)
}

function onUpdateModelValue() {
  // const index = activeKeys.value.findIndex(k => k === props.info?.key)
  // if (index >= 0) {
  //   activeKeys.value.splice(index, 1)
  // } else {
  //   activeKeys.value.push(props.info.key)
  // }
}

watch(deviceInited, val => {
  // if (val) {
  //   startRefreshScreen()
  // } else {
  //   stopRefreshScreen()
  // }
})

function closeWebsocket() {
  socketRef.value?.close()
}

function initWebsocket(wsUrl) {
  closeWebsocket()

  const socket = io(wsUrl, {
    reconnection: false,
    retries: 0
  })

  socket.on('image', (data) => {
    // console.log('收到图片数据，大小:', data.byteLength, '字节');

    // 将二进制数据转换为Blob
    const blob = new Blob([data], { type: 'image/png' });

    // 将Blob转换为DataURL
    const reader = new FileReader();
    reader.onload = (e) => {
      // 显示图片
      // imgPath.value = 
      $emits('changeImgPath', e.target.result)
    };
    reader.readAsDataURL(blob);
  });

  socket.on('connect', () => {
    socketRef.value = socket
    sendMsg('init', props.info)
    socket.on('init-done', initDone)
  });

  socket.on('disconnect', () => {
    console.log('Disconnected from server');
    socketRef.value = null
  });
}

watch(() => props.info?.key, val => {
  if (!props.info?.wsUrl) {
    return
  }

  initWebsocket(props.info.wsUrl)
}, {
  immediate: true,
  deep: true
})

const lastPos = shallowRef()

function getTouchUp() {
  const deviceId = props.info.key
  let ret

  if (lastPos.value) {
    ret = {
      type: 'touchUp',
      data: {
        deviceId,
        x: lastPos.value.x,
        y: lastPos.value.y,
      }
    }
    lastPos.value = null
  }

  return ret
}

function getCommands(direction, moveCenter) {
  const deviceId = props.info.key
  const startPos = {
    x: moveCenter.x,
    y: moveCenter.y
  }
  const count = 5
  const step = moveCenter.distance / count

  const arr = [
    getTouchUp(),
    {
      type: 'touchDown',
      data: {
        deviceId,
        ...startPos
      }
    }
  ].filter(Boolean)

  for (let i of [1, 2]) {
    const pos = {
      x: moveCenter.x,
      y: moveCenter.y
    }

    switch (direction) {
      case 'left':
        pos.x -= i * step
        break
      case 'right':
        pos.x += i * step
        break
      case 'up':
        pos.y -= i * step
        break
      case 'down':
        pos.y += i * step
        break
    }

    arr.push({
      type: 'touchMove',
      data: {
        deviceId,
        ...pos
      }
    })
  }

  lastPos.value = { ...arr[arr.length - 1]?.data }

  return arr
}

defineExpose({
  get key() {
    return props.info?.key
  },
  sendCommandWithCommands(commands) {
    const type = commands.type
    const code = commands.code
    const allCodes = commands.allCodes || []
    const keyMap = props.info?.keyMap?.[code]
    const moveCenter = props.info?.moveCenter
    if (type === 'keydown' && keyMap) {
      sendCommand({
        type: 'tap',
        data: {
          deviceId: props.info.key,
          x: keyMap.x,
          y: keyMap.y
        }
      })
    } else if (type === 'keydown' && moveCenter.left === code) {
      sendCommand(getCommands('left', moveCenter))
    } else if (type === 'keydown' && moveCenter.up === code) {
      sendCommand(getCommands('up', moveCenter))
    } else if (type === 'keydown' && moveCenter.down === code) {
      sendCommand(getCommands('down', moveCenter))
    } else if (type === 'keydown' && moveCenter.right === code) {
      sendCommand(getCommands('right', moveCenter))
    } else if (type === 'keyup' && [moveCenter.left, moveCenter.up, moveCenter.down, moveCenter.right].includes(code)) {
      sendCommand(getTouchUp())
    } else if (type && commands.data) {
      sendCommand({
        type, data: {
          ...commands.data,
          deviceId: props.info.key,
        }
      })
    }
  }
})

onBeforeUnmount(() => {
  const socket = toValue(socketRef)
  stopRefreshScreen()
  sendMsg('close-device', props.info)
  socket?.off('init-done', initDone)
  closeWebsocket()
})
</script>
<style lang="scss" scoped></style>